function Vue(options) {
  this.$options = options || {};
  // 监听data
  if (this.$options.data) {
    initData(this);
  };
  // create 函数
  if (options.create) {
    options.create.call(this);
  }
  // 处理事件
  // methods 方法绑定到this
  if (this.$options.methods) {
    let methods = this.$options.methods;
    for (key in methods) {
      this[key] = methods[key].bind(this);
    }
  };

  // 节点绑定渲染
  if (this.$options.el) {
    this.mount(this.$options.el);
  };
}

Vue.prototype.mount = function (el) {
  let root = document.querySelector(el);
  const {
    template
  } = this.$options;
  if (template) {
    this._ast = parse(template);
  } else {
    this._ast = parse(root.innerHTML);
  }

  this._render = generateRender(this, this._ast);
  console.log(this._render);
  new Watcher(() => {
    this.render(root);
  });
}

Vue.prototype.render = function (root) {
  if (!root) {
    console.warn('root 不存在');
  }
  // if (document.createDocumentFragment()) {
  //   let fragment = document.createDocumentFragment();
  //   DFS(fragment, this._ast, this);
  //   [...root.children].forEach((child) => {
  //     root.removeChild(child);
  //   });
  //   root.appendChild(fragment);
  // } else {
  //   if (root.children) {
  //     [...root.children].forEach((child) => {
  //       root.removeChild(child);
  //     });
  //   }
  //   // console.log(this._render(this));
  //   root.appendChild(this._render(this));
  // }

  if (root.children) {
    [...root.children].forEach((child) => {
      root.removeChild(child);
    });
  }
  // console.log(this._render(this));
  root.appendChild(this._render(this));
}

Vue.prototype.createDom = function (tag, data, children) {
  let dom = document.createElement(tag);
  for (let key in data.attrs) {
    dom.setAttribute(key, data.attrs[key]);
  }
  for (let key in data.events) {
    dom.addEventListener(key, data.events[key]);
  }
  children.forEach((child) => {
    dom.appendChild(child);
  });
  return dom;
}

Vue.prototype.createText = function (text) {
  return document.createTextNode(text);
}

Vue.prototype.createFor = function (obj, fn) {
  let ret = [];
  if (isObject(obj)) {
    for (let key in obj) {
      ret.push(fn(key, obj[key]));
    }
  } else if (isArray(obj)) {
    obj.forEach((item, index) => {
      ret.push(fn(index, item));
    });
  };
  return ret;
}

function initData(vm) {
  let data = vm.$options.data;
  vm._data = observe(data);
  for (let key in data) {
    Object.defineProperty(vm, key, {
      configurable: true,
      enumerable: true,
      get() {
        return vm._data[key]
      },
      set(value) {
        vm._data[key] = value
      }
    });
  }
}
/////////////////
const dataReg1 = /\{\{([^{}]*)\}\}/g;
// 深度优先遍历ast
function DFS(parent, ast, mvvm, forData = {}) {
  // 文本节点的处理
  if (ast.type === 'text') {
    let text = ast.value.replace(dataReg1, function (a, b) {
      return getObjValue(b, forData, mvvm);
    });
    parent.appendChild(document.createTextNode(text));
    // for循环的处理
  } else if (ast.for) {
    let obj = getObjValue(ast.forObj, forData, mvvm);
    if (isArray(obj)) {
      obj.forEach((item, index) => {
        DFS(parent, Object.assign({}, ast, {
          for: false
        }), mvvm, Object.assign({}, forData, {
          [ast.forKey]: index,
          [ast.forValue]: item
        }));
      });
    }
    if (isObject(obj)) {
      for (let key in obj) {
        DFS(parent, Object.assign({}, ast, {
          for: false
        }), mvvm, Object.assign({}, forData, {
          [ast.forKey]: key,
          [ast.forValue]: obj[key]
        }));
      }
    }
    // if处理
  } else if (ast.if) {
    if (ast.ifFalse && !getObjValue(ast.ifValue, forData, mvvm) || !ast.ifFalse && getObjValue(ast.ifValue, forData, mvvm)) {
      DFS(parent, ast.ifCondition, mvvm, forData);
    } else if (ast.elseCondition) {
      DFS(parent, ast.elseCondition, mvvm, forData);
    };
    // 普通节点的处理
  } else {
    let dom = document.createElement(ast.name);
    if (ast.attrs) {
      attrsHander(dom, ast.attrs, mvvm, forData)
    };
    if (ast.children) {
      ast.children.forEach((child) => {
        DFS(dom, child, mvvm, forData);
      });
    };
    parent.appendChild(dom);
  }
}
// 获取对象的值
function getObjValue(key, ...objs) {
  let paramsArr = key.match(/([a-zA-Z_][\w]*)/g);
  let result = undefined;
  for (let i = 0; i < objs.length; i++) {
    result = paramsArr.reduce((prev, next) => {
      return prev[next];
    }, objs[i]);
    if (result !== undefined) {
      return result;
    }
  }
}
// 属性的处理
function attrsHander(dom, attrs, mvvm, forData = {}) {
  attrs.forEach((item) => {
    // @绑定事件
    if (item.key[0] === '@') {
      dom.addEventListener(item.key.slice(1), (event) => {
        getObjValue(item.value, mvvm)(event);
      });
      // 绑定数据
    } else if (item.key[0] === ':') {
      dom.setAttribute(item.key.slice(1), getObjValue(item.value, forData, mvvm));
      // 普通数据
    } else {
      dom.setAttribute(item.key, item.value);
    }
  });
}
/////////////////
// 生成render函数
function generateRender(mvvm, ast) {
  let code = genCode(ast);
  let result = `with(mvvm){return ${code}}`;
  return new Function('mvvm', result);
}
// 生产render字符串
function genCode(ast) {
  if (ast.type === 'text') {
    // return `createText(${genText(ast.value.replace(/\s*/, ' '))})`
    return `createText(${ast.value})`
  } else if (ast.for) {
    return `...createFor(${ast.forObj}, function(${ast.forKey},${ast.forValue}){ return ${genCode(Object.assign({}, ast, {for: false}))}})`
  } else if (ast.if) {
    return `(${ast.ifValue}) ? ${genCode(ast.ifCondition)} : ${genCode(ast.elseCondition)}`
  } else {
    return `createDom("${ast.name}",${genData(ast)} ,[${ast.children.map(genCode).join(',')}])`;
  }
}

// 生成dom绑定的属性事件等
function genData(ast) {
  let data = '{';
  let attrs = `attrs:{`,
    events = [];
  ast.attrs.forEach((item) => {
    // @绑定事件
    if (item.key[0] === '@') {
      events.push([item.key.slice(1), item.value]);
      // 绑定数据
    } else if (item.key[0] === ':') {
      attrs += `"${item.key.slice(1)}": ${item.value},`
      // 普通数据
    } else {
      attrs += `"${item.key}": "${item.value}",`
    }
  });
  attrs = attrs.replace(/,$/, '') + '}';
  return `${data}${attrs},${genEvents(events)}}`
}

function genEvents(events) {
  let on = `events:{`;
  events.forEach((item) => {
    if (item[1].endsWith(')')) {
      on += `"${item[0]}": function($event){ ${(item[1])} },`;
    } else {
      on += `"${item[0]}": ${item[1]},`;
    }
  });
  on = on.replace(/,$/, '') + '}';
  return on;
}